include("Libraries/LiteGUI/litegui.min.js")

include("Editor/Tools/MoveTool.js")
include("Editor/Tools/ResizeTool.js")
include("Editor/Tools/RotateTool.js")

include("Editor/UI.js")

function Editor() {}

Editor.STATE_IDLE = 8
Editor.STATE_EDITING = 9
Editor.STATE_TESTING = 11

Editor.MODE_SELECT = 0
Editor.MODE_MOVE = 1
Editor.MODE_RESIZE = 2
Editor.MODE_ROTATE = 3

Editor.initialise = () => {
  UI.initialise()

  Editor.toolMode = Editor.MODE_SELECT
  Editor.state = Editor.STATE_EDITING

  Editor.pid2 = Math.PI / 2.0

  Editor.selectedObject = null
  Editor.blockCameraMove = false
  Editor.editingObject = false
  Editor.editingObjectArgs = null

  Editor.canvas = UI.canvas
  Mouse.canvas = Editor.canvas

  Editor.program = null
  Editor.level = null
  Editor.createNewProgram()

  Editor.toolScene = new THREE.Scene()
  Editor.toolSceneTop = new THREE.Scene()
  Editor.cannonRenderer = new THREE.CannonDebugRenderer(Editor.toolScene, Editor.level.world)

  Editor.camera = new THREE.PerspectiveCamera(60, Editor.canvas.width/Editor.canvas.height, 0.1, 100000)
  Editor.camera.position.set(0, 5, -5)
  Editor.cameraRotation = new THREE.Vector2(0, 0)
  Editor.setCameraRotation(Editor.cameraRotation, Editor.camera)

  Editor.raycaster = new THREE.Raycaster()

  Editor.renderer = new THREE.WebGLRenderer({ canvas: Editor.canvas })
  Editor.renderer.autoClear = false
  Editor.renderer.setSize(Editor.canvas.width, Editor.canvas.height)
  Editor.renderer.shadowMap.enabled = true
  Editor.renderer.shadowMap.type = THREE.PCFSoftShadowMap

  Editor.gridHelper = new THREE.GridHelper(200, 5)
  Editor.toolScene.add(Editor.gridHelper)

  Editor.axisHelper = new THREE.AxisHelper(100)
  Editor.toolScene.add(Editor.axisHelper)

  Editor.boxHelper = new THREE.BoxHelper()
  Editor.toolScene.add(Editor.boxHelper)

  Editor.moveTool = new MoveTool()
  Editor.moveTool.visible = false
  Editor.toolSceneTop.add(Editor.moveTool)

  Editor.resizeTool = new ResizeTool()
  Editor.resizeTool.visible = false
  Editor.toolSceneTop.add(Editor.resizeTool)

  Editor.rotateTool = new RotateTool()
  Editor.rotateTool.visible = false
  Editor.toolSceneTop.add(Editor.rotateTool)

  Editor.resize()
}

Editor.update = () => {

  Editor.blockCameraMove = false

  if (Editor.state === Editor.STATE_EDITING) {
    if (Editor.selectedObject !== null) {
      Editor.boxHelper.visible = true
      Editor.boxHelper.update(Editor.selectedObject)

      if (Editor.toolMode === Editor.MODE_MOVE) {
        Editor.moveTool.visible = true
        Editor.rotateTool.visible = false
        Editor.resizeTool.visible = false

        var distance = Editor.camera.position.distanceTo(Editor.selectedObject.position) / 5
        Editor.moveTool.scale.set(distance, distance, distance)
        Editor.moveTool.position.copy(Editor.selectedObject.position)
      } else if (Editor.toolMode === Editor.MODE_RESIZE) {
        Editor.moveTool.visible = false
        Editor.rotateTool.visible = false
        Editor.resizeTool.visible = true

        var distance = Editor.camera.position.distanceTo(Editor.selectedObject.position) / 5
        Editor.resizeTool.scale.set(distance, distance, distance)
        Editor.resizeTool.rotation.copy(Editor.selectedObject.rotation)
        Editor.resizeTool.position.copy(Editor.selectedObject.position)
      } else if (Editor.toolMode === Editor.MODE_ROTATE) {
        Editor.moveTool.visible = false
        Editor.rotateTool.visible = true
        Editor.resizeTool.visible = false

        var distance = Editor.camera.position.distanceTo(Editor.selectedObject.position) / 5
        Editor.rotateTool.scale.set(distance, distance, distance)
        Editor.rotateTool.position.copy(Editor.selectedObject.position)
      }
    } else {
      Editor.moveTool.visible = false
      Editor.rotateTool.visible = false
      Editor.resizeTool.visible = false
      Editor.boxHelper.visible = false
    }

    if (Editor.editingObject) {
      if (Mouse.buttonJustReleased(Mouse.LEFT)) {
        Editor.editingObject = false
      } else {
        Editor.blockCameraMove = true

        if (Editor.toolMode === Editor.MODE_MOVE) {
          var speed = Editor.camera.position.distanceTo(Editor.selectedObject.position) / 500

          if (Editor.editingObjectArgs.x) {
            Editor.selectedObject.position.x -= Mouse.posDiff.x * speed * Math.sin(Editor.cameraRotation.x)
            Editor.selectedObject.position.x -= Mouse.posDiff.x * speed * Math.cos(Editor.cameraRotation.x)
          } else if (Editor.editingObjectArgs.y) {
            Editor.selectedObject.position.y -= Mouse.posDiff.y * speed
          } else if (Editor.editingObjectArgs.z) {
            Editor.selectedObject.position.z -= Mouse.posDiff.y * speed * Math.sin(Editor.cameraRotation.x + Editor.pid2)
            Editor.selectedObject.position.z -= Mouse.posDiff.x * speed * Math.cos(Editor.cameraRotation.x + Editor.pid2)
          }
        } else if (Editor.toolMode === Editor.MODE_RESIZE) {
          var speed = Editor.camera.position.distanceTo(Editor.selectedObject.position)/1000

          if (Editor.editingObjectArgs.x) {
            Editor.selectedObject.scale.x -= Mouse.posDiff.x * speed * Math.sin(Editor.cameraRotation.x)
            Editor.selectedObject.scale.x -= Mouse.posDiff.x * speed * Math.cos(Editor.cameraRotation.x)
          } else if (Editor.editingObjectArgs.y) {
            Editor.selectedObject.scale.y -= Mouse.posDiff.y * speed
          } else if (Editor.editingObjectArgs.z) {
            Editor.selectedObject.scale.z -= Mouse.posDiff.y * speed * Math.sin(Editor.cameraRotation.x + Editor.pid2)
            Editor.selectedObject.scale.z -= Mouse.posDiff.x * speed * Math.cos(Editor.cameraRotation.x + Editor.pid2)
          }
        } else if (Editor.toolMode === Editor.MODE_ROTATE) {
          var speed = Editor.camera.position.distanceTo(Editor.selectedObject.position) / 500

          if (Editor.editingObjectArgs.x) {
            Editor.selectedObject.rotation.x -= Mouse.posDiff.y * speed
            Editor.selectedObject.rotation.x -= Mouse.posDiff.x * speed
          } else if (Editor.editingObjectArgs.y) {
            Editor.selectedObject.rotation.y -= Mouse.posDiff.y * speed
            Editor.selectedObject.rotation.y -= Mouse.posDiff.x * speed
          } else if (Editor.editingObjectArgs.z) {
            Editor.selectedObject.rotation.z -= Mouse.posDiff.y * speed
            Editor.selectedObject.rotation.z -= Mouse.posDiff.x * speed
          }
        }
      }
    }

    if (Mouse.insideCanvas()) {

      if (Editor.toolMode === Editor.MODE_SELECT) {
        if (Mouse.buttonJustPressed(Mouse.LEFT)) {
          Editor.updateRaycaster()
          var intersects = Editor.raycaster.intersectObjects(Editor.level.children, true)
          if (intersects.length > 0) {
            Editor.selectedObject = intersects[0].object
          }
        }
      } else if (Editor.toolMode === Editor.MODE_MOVE) {
        Editor.updateRaycaster()
        var move = Editor.moveTool.highlightSelectedComponents(Editor.raycaster)

        if (move.selected && Mouse.buttonJustPressed(Mouse.LEFT)) {
          Editor.editingObjectArgs = move
          Editor.editingObject = true
          Editor.blockCameraMove = true
        }
      } else if (Editor.toolMode === Editor.MODE_RESIZE) {
        Editor.updateRaycaster()
        var resize = Editor.resizeTool.highlightSelectedComponents(Editor.raycaster)

        if (resize.selected && Mouse.buttonJustPressed(Mouse.LEFT)) {
          Editor.editingObjectArgs = resize
          Editor.editingObject = true
          Editor.blockCameraMove = true
        }
      } else if (Editor.toolMode === Editor.MODE_ROTATE) {
        Editor.updateRaycaster()
        var rotate = Editor.rotateTool.highlightSelectedComponents(Editor.raycaster)

        if (rotate.selected && Mouse.buttonJustPressed(Mouse.LEFT)) {
          Editor.editingObjectArgs = rotate
          Editor.editingObject = true
          Editor.blockCameraMove = true
        }
      }

      if (Mouse.buttonPressed(Mouse.LEFT) && !Editor.blockCameraMove) {
        Editor.cameraRotation.x -= 0.01 * Mouse.SENSITIVITY * Mouse.posDiff.x
        Editor.cameraRotation.y -= 0.01 * Mouse.SENSITIVITY * Mouse.posDiff.y

        var pid2 = 1.57
        if (Editor.cameraRotation.y < -pid2) {
          Editor.cameraRotation.y = -pid2
        } else if (Editor.cameraRotation.y > pid2) {
          Editor.cameraRotation.y = pid2
        }

        Editor.setCameraRotation(Editor.cameraRotation, Editor.camera)
      } else if (Mouse.buttonPressed(Mouse.RIGHT)) {
        var speed = 0.1
        var angleCos = Math.cos(Editor.cameraRotation.x)
        var angleSin = Math.sin(Editor.cameraRotation.x)

        Editor.camera.position.z += Mouse.posDiff.y * speed * angleCos
        Editor.camera.position.x += Mouse.posDiff.y * speed * angleSin

        var angleCos = Math.cos(Editor.cameraRotation.x + Editor.pid2)
        var angleSin = Math.sin(Editor.cameraRotation.x + Editor.pid2)

        Editor.camera.position.z += Mouse.posDiff.x * speed * angleCos
        Editor.camera.position.x += Mouse.posDiff.x * speed * angleSin
      }

      if (Mouse.wheel !== 0) {
        var direction = Editor.camera.getWorldDirection()
        var speed = 0.01 * Mouse.wheel
        Editor.camera.position.x -= speed * direction.x
        Editor.camera.position.y -= speed * direction.y
        Editor.camera.position.z -= speed * direction.z
      }
    }
  } else if (Editor.state === Editor.STATE_TESTING) {
    Editor.level.update()
  }
}

Editor.addToActualLevel = (obj) => {
  Editor.level.add(obj)
}

Editor.draw = () => {
  Editor.renderer.clear()
  Editor.renderer.render(Editor.level, Editor.camera)

  if (Editor.state === Editor.STATE_EDITING) {
    Editor.cannonRenderer.update()
    Editor.renderer.render(Editor.toolScene, Editor.camera)
    //Editor.renderer.clearDepth()
    Editor.renderer.render(Editor.toolSceneTop, Editor.camera)
  }

  Editor.renderer.render(Editor.level, Editor.camera)
}

Editor.resize = () => {
  UI.resize()

  Editor.canvas.style.width = Editor.canvas.width + "px"
  Editor.canvas.style.height = Editor.canvas.height + "px"

  Editor.resizeCamera()
}

Editor.resizeCamera = () => {
  Editor.renderer.setSize(Editor.canvas.width, Editor.canvas.height)
  Editor.camera.aspect = Editor.canvas.width / Editor.canvas.height
  Editor.camera.updateProjectionMatrix()
}

Editor.setCameraRotation = (cameraRotation, camera) => {
  var cosAngleY = Math.cos(cameraRotation.y)
  var direction = new THREE.Vector3(
                                    Math.sin(cameraRotation.x) * cosAngleY,
                                    Math.sin(cameraRotation.y),
                                    Math.cos(cameraRotation.x) * cosAngleY
                                   )

  direction.x += camera.position.x
  direction.y += camera.position.y
  direction.z += camera.position.z
  camera.lookAt(direction)
}

Editor.updateRaycaster = () => {
  var mouse = new THREE.Vector2((Mouse.pos.x/Editor.canvas.width) * 2 - 1, -(Mouse.pos.y/Editor.canvas.height) * 2 + 1)
  Editor.raycaster.setFromCamera(mouse, Editor.camera)
}

Editor.resetEditingFlags = () => {
  Editor.selectedObject = null
  Editor.blockCameraMove = false
  Editor.editingObject = false
  Editor.editingObjectArgs = null
}

Editor.createNewProgram = () => {
  Editor.program = new Program()
  Editor.program.addDefaultLevel()
  Editor.level = Editor.program.actualLevel

  Editor.resetEditingFlags()
}
